/**
 * All Rights Reserved , Copyright (C) 2020 , 青岛鼎信通讯股份有限公司
 * <p>
 * MeetRoomApplyService
 * 会议室预订申请
 * <p>
 * 修改纪录
 * 2020-10-26 版本：1.0 donghang 创建。
 *
 * @version 版本：1.0
 * @author 作者：donghang
 * 创建日期：2020-10-26
 */
package com.topscomm.meet.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencentcloudapi.wemeet.common.constants.InstanceEnum;
import com.tencentcloudapi.wemeet.common.constants.RestErrorCode;
import com.tencentcloudapi.wemeet.common.exception.WemeetSdkException;
import com.tencentcloudapi.wemeet.models.MeetingSetting;
import com.tencentcloudapi.wemeet.models.meeting.*;
import com.topscomm.base.BaseRemindTemplate;
import com.topscomm.base.BaseSystemConst;
import com.topscomm.base.pojo.*;
import com.topscomm.base.service.IBaseCboUserExtendService;
import com.topscomm.base.service.IBaseRemindTaskService;
import com.topscomm.base.service.impl.BasePermissionManageHistoryService;
import com.topscomm.base.service.impl.BasePermissionManageService;
import com.topscomm.base.service.impl.BaseRemindConfigHistoryService;
import com.topscomm.base.service.impl.BaseRemindConfigService;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.cbo.pojo.CboApprovalNodeEntity;
import com.topscomm.cbo.pojo.CboApprovalNodeInsEntity;
import com.topscomm.cbo.pojo.CboDeptEntity;
import com.topscomm.cbo.pojo.CboRoleEntity;
import com.topscomm.cbo.service.ICboApprovalFlowInsService;
import com.topscomm.cbo.service.ICboRoleService;
import com.topscomm.cbo.service.impl.CboApprovalNodeInsService;
import com.topscomm.cbo.service.impl.CboDeptService;
import com.topscomm.meet.MeetSystemConst;
import com.topscomm.meet.MeetSystemConst.MeetRoomTypeEnum;
import com.topscomm.meet.pojo.*;
import com.topscomm.meet.service.IMeetManageService;
import com.topscomm.meet.service.IMeetRoomApplyService;
import com.topscomm.meet.service.impl.auto.MeetRoomApplyServiceAuto;
import com.topscomm.meet.utils.TencentMeetUtil;
import com.topscomm.mis.IMisDao;
import com.topscomm.mis.MisEntity;
import com.topscomm.pub.util.*;
import com.topscomm.tap.ITapDao;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.common.*;
import com.topscomm.tap.lock.ZookeeperDistributeLock;
import com.topscomm.work.WorkSystemConst;
import com.topscomm.work.pojo.WorkScheduleEntity;
import com.topscomm.work.service.impl.WorkScheduleService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service(value = "meetRoomApplyService")
@Scope(value = "singleton")
@Slf4j
public class MeetRoomApplyService extends MeetRoomApplyServiceAuto implements IMeetRoomApplyService {
    private final MeetRoomApplyService self;

    public MeetRoomApplyService(@Lazy MeetRoomApplyService self) {
        this.self = self;
    }

    @Resource(name = "flowDatacodeCache")
    protected FlowDatacodeCache flowDatacodeCache;

    @Resource(name = "meetRoomManageService")
    private MeetRoomManageService meetRoomManageService;
    @Resource(name = "meetManageHistoryService")
    private MeetManageHistoryService meetManageHistoryService;
    @Resource(name = "basePermissionManageService")
    private BasePermissionManageService basePermissionManageService;
    @Resource(name = "basePermissionManageHistoryService")
    private BasePermissionManageHistoryService basePermissionManageHistoryService;
    @Resource(name = "meetPersonRecordService")
    private MeetPersonRecordService meetPersonRecordService;
    @Resource(name = "meetPersonRecordHistoryService")
    private MeetPersonRecordHistoryService meetPersonRecordHistoryService;
    @Resource(name = "baseRemindConfigService")
    private BaseRemindConfigService baseRemindConfigService;
    @Resource(name = "baseRemindConfigHistoryService")
    private BaseRemindConfigHistoryService baseRemindConfigHistoryService;

    @Autowired
    private IBaseCboUserExtendService baseCboUserExtendService;

    @Autowired
    private ICboRoleService cboRoleService;

    @Autowired
    private IBaseRemindTaskService baseRemindTaskService;

    @Autowired
    private IMeetManageService meetManageService;
    @Autowired
    DatacodeCache datacodeCache;

    @Autowired
    private ZookeeperDistributeLock lock;

    // 提前一天通知
    private static final String RemindTime = "1";

    // 日程标题
    private static final String WorkTitle = "会议室会前准备";

    // 模板类型
    private static final String Templatetype = "ExtraContentTemplate";

    /**
     * @param entity
     * @description:
     * @author: donghang
     * @date: 2020年10月26日下午6:21:09
     * @modify:
     */
    @Override
    protected void beforeInsert(BasicEntity entity) {
        super.beforeInsert(entity);
        // 审批字段赋值
        if (entity.getId() <= 0) {// 赋值Id和单号
            long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
            entity.setId(arrayId[0]);
            String docNo = String.valueOf(arrayId[0]);
            docNo = "HYS" + docNo.substring(0, 6) + docNo.substring(9);
            entity.setValue(MeetRoomApplyEntity.FieldDocno, docNo);
        }
        MeetRoomApplyEntity meetRoomApplyEntity = (MeetRoomApplyEntity) entity;
        meetRoomApplyEntity.setDocdate(new Date());
        meetRoomApplyEntity.setUsercode(this.getSessionUserBean().getUser().getCode());
        meetRoomApplyEntity.setUsername(this.getSessionUserBean().getUser().getName());
        meetRoomApplyEntity.setDeptcode(this.getSessionUserBean().getDept().getCode());
        meetRoomApplyEntity.setOrgcode(this.getSessionUserBean().getOrg().getCode());
        // 合法性检查
        this.checkDataValid(meetRoomApplyEntity);
    }

    /**
     * @description:
     * @author: donghang
     * @date: 2020年10月26日下午6:28:47
     * @modify:
     */
    @Override
    protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
            MeetRoomApplyEntity meetRoomApplyEntity = (MeetRoomApplyEntity) entity;
            String roomType = datacodeCache.getValueDynamic("MeetAllRoomType", ConvertUtil.convertToString(meetRoomApplyEntity.getMeetroomid()), "id", "name");
            // 合法性检查
            this.checkDataValid(meetRoomApplyEntity);
            //提交审批之前 若为线上会议室审批 重置会议主表信息
            //赋值远程会议信息
            if (MeetRoomTypeEnum.Remote.contentEquals(roomType)) {
                String remoteMeetInfo = datacodeCache.getValueDynamic(MeetRoomManageEntity.tableName, ConvertUtil.convertToString(meetRoomApplyEntity.getMeetroomid()), "id", "name");
                Map<String, Object> updateMap = new HashMap<>();
                updateMap.put("id", meetRoomApplyEntity.getSourceid());
                updateMap.put(MeetManageEntity.FieldRemotemeetinfo, remoteMeetInfo + ParameterCache.getValue(MeetSystemConst.RemoteInfoAppendText));
                meetManageService.update(updateMap);
            }
    }

    /**
     * @description:
     * @author: donghang
     * @date: 2020年10月26日下午6:31:09
     * @modify:
     */
    @Override
    protected void updateBefore(Map<String, Object> map) throws ServiceException {
        MeetRoomApplyEntity meetRoomApplyEntity = new MeetRoomApplyEntity();
        meetRoomApplyEntity = (MeetRoomApplyEntity) meetRoomApplyEntity.convertFromMap(map);
        // 合法性检查
        this.checkDataValid(meetRoomApplyEntity);
    }

    /**
     * 检查数据有效性
     *
     * @description:
     * @author: donghang
     * @date: 2020年10月26日下午6:32:08
     * @modify:
     */
    private void checkDataValid(MeetRoomApplyEntity meetRoomApplyEntity) {
        // 比较时间
        Date begintime = meetRoomApplyEntity.getBegintime();
        Date endtime = meetRoomApplyEntity.getEndtime();
        if (begintime == null || endtime == null) {
            return;
        }
        if (begintime.compareTo(endtime) >= 0) {
            throw new ServiceException("您输入的时间有误，请重新输入！");
        }
        // 校验会议室是否被占用
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" 1=1 ");
        sql.appendLineSingle(" and state in (1,9) and meetroomid = {0} and begintime <{1} and endtime >{2} and id<>{3}",
                meetRoomApplyEntity.getMeetroomid(),
                SQLAdapter.toDateLong(DateUtil.dateToString(endtime, "yyyy-MM-dd HH:mm:ss")),
                SQLAdapter.toDateLong(DateUtil.dateToString(begintime, "yyyy-MM-dd HH:mm:ss")),
                meetRoomApplyEntity.getId());
        List<MeetRoomApplyEntity> meetRoomApplyEntities = this.queryByWhere(sql.toString());
        if (meetRoomApplyEntities.size() > 0) {
            MeetRoomApplyEntity applyEntity = meetRoomApplyEntities.get(0);
            // 除了重新发布同一个会议以外，其他情况都提示时间冲突
            if (!("MeetManage".equals(applyEntity.getSourcetype()) &&
                    applyEntity.getSourceid().equals(meetRoomApplyEntity.getSourceid()))) {
                throw new ServiceException(meetRoomApplyEntity.getAirlinecompany() + "已经被占用，请选择其他时间段！");
            }
        }
    }

    /**
     * 查看会议室近期的单独申请的预约记录，根据时间查看
     *
     * @param paraMap
     * @return
     * @description:
     * @author: donghang
     * @date: 2020年10月28日上午10:21:30
     * @modify:
     */
    @Override
    public List<Map<String, Object>> queryRecentlyIndependApplyList(Map<String, Object> paraMap) {
        List<Map<String, Object>> applyList = new ArrayList<>();
        StringBufferProxy sql = new StringBufferProxy();
        // 查询会议室的单独预约的记录，注意sourceid没有
        sql.appendSingle("enabled=1 and state in (1,9) and meetroomid is not null");
        if (paraMap.containsKey("qry_begintime")) {
            String start = paraMap.get("qry_begintime").toString();
            sql.appendSingle(" and endtime > {0}", SQLAdapter.toDateLong(start));
        }
        if (paraMap.containsKey("qry_endtime")) {
            String end = paraMap.get("qry_endtime").toString();
            sql.appendSingle(" and begintime < {0} ", SQLAdapter.toDateLong(end));
        }
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("qry_wheresql", sql.toString());
        applyList.addAll(this.queryMap(queryMap, "queryMeetApplyInfoList"));
        return applyList;
    }

    /**
     * @param entity
     * @param sessionUserBean
     * @description: 会议室申请对外接口
     * @author: wanghongwei
     * @date: 2020-11-2 16:28:15
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(String roomType, MeetRoomApplyEntity entity, SessionUserBean sessionUserBean) {
        try {
            this.lock.getLock(ConvertUtil.convertToString(entity.getMeetroomid()));
            List<Map<String, Object>> flowIdList = flowDatacodeCache.getApprovalFlowListMap("ApprovalFlow_MeetRoomApply",
                    sessionUserBean, MeetManageEntity.FieldSortcode);
            if (flowIdList.size() == 0) {
                throw new ServiceException("没有配置审批流");
            }
            // 默认新申请的不是线上
            boolean isRemote = false;
            entity.setFlowid(ConvertUtil.convertToLong(flowIdList.get(0).get("id")));
            String deptName = sessionUserBean.getDept().getFullname();
            StringBufferProxy mainTitle = new StringBufferProxy();
            mainTitle.appendSingle("{0}{1}于{2}提交会议室预订申请申请,单据编号{3}! ", deptName, entity.getUsername(),
                    DateUtil.dateToString(new Date(), "yyyy-MM-dd"), entity.getDocno());
            //查询会议管理
            MeetManageEntity meetManageEntity = meetManageService.queryById(entity.getSourceid());
            // 查询会议室
            boolean needApproval = false;
            if (entity.getMeetroomid() > 0) {
                MeetRoomManageEntity meetRoomManageEntity = this.meetRoomManageService
                        .queryById(ConvertUtil.convertToString(entity.getMeetroomid()));
                String meetRoomType = ConvertUtil.convertToString(meetRoomManageEntity.getType());
                if (meetRoomManageEntity != null && (MeetRoomTypeEnum.Remote.contentEquals(meetRoomType) || MeetRoomTypeEnum.Company.contentEquals(meetRoomType))) {
                    needApproval = true;
                }
                // 新申请的会议室是线上
                if (meetRoomManageEntity != null && MeetRoomTypeEnum.Remote.contentEquals(meetRoomType)) {
                    isRemote = true;
                }
            }
            // 查询来源单子的会议室
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle(" 1=1");
            sql.appendSingle(" and sourceid = '{0}'", entity.getSourceid());
            sql.appendSingle(" and sourcetype = '{0}'", entity.getSourcetype());
            sql.appendSingle("AND (SELECT TYPE FROM MEETROOMMANAGE ROOM  WHERE ROOM.ID = MEETROOMID) = '{0}'", roomType);
            List<MeetRoomApplyEntity> entityList = this.queryByWhere(sql.toString());
            if (entityList.size() > 0) {
                // 若entityList长度为1，且该记录状态为0，则是会议创建时产生的会议室申请记录
                if (entityList.size() == 1 && entityList.get(0).getState() == 0) {
                    if (needApproval) {
                        if (isRemote) {
                            meetManageEntity.setState(MeetSystemConst.MeetStateEnum.Submit);
                            meetManageService.updateEntity(meetManageEntity);
                        }
                        this.executeSubmit(entity, mainTitle.toString(), sessionUserBean);
                        this.afterRoomSubmit(entityList.get(0), roomType);
                    }
                } else {
                    // 发布变更
                    for (MeetRoomApplyEntity meetRoomApplyEntity : entityList) {
                        long existMeetRoomId = meetRoomApplyEntity.getMeetroomid();
                        Date existBeginTime = meetRoomApplyEntity.getBegintime();
                        Date existEndTime = meetRoomApplyEntity.getEndtime();
                        int state = meetRoomApplyEntity.getState();
                        //变更了会议室 或者 时间
                        if (existMeetRoomId != entity.getMeetroomid() || existBeginTime.compareTo(entity.getBegintime()) != 0
                                || existEndTime.compareTo(entity.getEndtime()) != 0) {
                            String id = ConvertUtil.convertToString(meetRoomApplyEntity.getId());
                            // 新申请的不是线上的时候,且本次会议不申请线上的时候，释放以前申请的会议室资源
                            if (!isRemote && ConvertUtil.convertToString(meetManageEntity.getRemoteroomid()).isEmpty()) {
                                // 取消之前的会议室审批并删除记录
                                this.executeDelApprove(id, sessionUserBean);
                                this.deleteById(id);
                            }
                            // 公司级会议室重新提交审批
                            if (needApproval) {
                                this.executeSubmit(entity, mainTitle.toString(), sessionUserBean);
                                this.afterRoomSubmit(meetRoomApplyEntity, roomType);
                            }
                        } else {
                            // 未产生变更
                            // 若该会议室申请记录不为暂存状态，且会议室id，开始结束时间都相同，则用暂存状态的会议室记录更新该记录
                            if (state != 0) {
                                this.deleteById(ConvertUtil.convertToString(entity.getId()));
                                this.updateOldApplyByNewApply(meetRoomApplyEntity, entity);
                                if (meetManageEntity.getRemoteroomid() > 0 && roomType.equals(MeetRoomTypeEnum.Remote)) {
                                    meetManageEntity.setVersion(meetManageEntity.getVersion() - 1);
                                    meetManageEntity.setState(1);
                                    meetManageService.updateEntity(meetManageEntity);
                                }

                            }
                        }
                    }
                }
            } else {
                //创建时 默认走这个
                // 公司级会议室重新提交审批
                if (needApproval) {
                    this.executeSubmit(entity, mainTitle.toString(), sessionUserBean);
                }
            }
        }finally {
            this.lock.releaseLock(ConvertUtil.convertToString(entity.getMeetroomid()));
        }
    }

    /***
     * @description: 提交审批操作之后
     * @param meetRoomApplyEntity
     * @return void
     * @author: wangxinhua
     * @date: 2023/3/30 11:42
     * @modify:
     */
    private void afterRoomSubmit(MeetRoomApplyEntity meetRoomApplyEntity, String roomType) {
        //保存会议历史版本信息，（公司级会议申请的才保存）
        this.saveMeetHistoryVersion(meetRoomApplyEntity, roomType);
    }

    /**
     * @return boolean
     * @description: 是否可进行历史版本记录
     * @author: wangxinhua
     * @date: 2023/3/30 22:04
     * @modify:
     */
    private boolean historyVersionValidate(MeetManageEntity meetManageEntity, String roomType) {
        //如果是线下转公司级线上生成历史
        //如果是公司级线上转公司级线上生成历史
        //其余均不生成历史
        boolean next = false;
        //版本号>0的才会生成历史
        if (meetManageEntity != null && meetManageEntity.getVersion() > 0) {
            //如果当前是线上公司级,且是生成远程会议室审批时
            if (meetManageEntity.getRemoteroomid() > 0 && roomType.equals(MeetRoomTypeEnum.Remote)) {
                next = true;
            }
        }
        return next;
    }

    /**
     * @return void
     * @description: 保存会议历史版本信息，（公司级会议申请的才保存）
     * @author: wangxinhua
     * @date: 2023/3/30 11:05
     * @modify:
     */
    private void saveMeetHistoryVersion(MeetRoomApplyEntity meetRoomApplyEntity, String roomType) {
        StringBufferProxy sql = new StringBufferProxy();
        // 查询线上+公司级会议申请
        MeetManageEntity meetManageEntity = meetManageService.queryById(meetRoomApplyEntity.getSourceid());
        //大于等于0是限制历史数据,只有远程生成历史版本
        if (this.historyVersionValidate(meetManageEntity, roomType)) {
            //是否是0版本
            boolean isInitVersion = false;
            if (meetManageEntity.getVersion() == 0) {
                isInitVersion = true;
            }
            MeetManageHistoryEntity meetManageHistoryEntity = new MeetManageHistoryEntity();
            BeanUtils.copyProperties(meetManageEntity, meetManageHistoryEntity);
            //设置默认值
            meetManageHistoryEntity.setMeetid(meetManageEntity.getId());
            meetManageHistoryEntity.setVersion(meetManageEntity.getVersion());
            //初始版本直接有效
            meetManageHistoryEntity.setValid(isInitVersion ? 1 : 0);
            long[] arrayId = PrimaryKeyUtil.GeneIDs(meetManageHistoryEntity.getTableName(), 1);
            meetManageHistoryEntity.setId(arrayId[0]);
            meetManageHistoryService.insert(meetManageHistoryEntity);
            // 人员权限表
            List<BasicEntity> addEntities = new ArrayList<BasicEntity>();
            sql.appendSingle(" sourceid={0} ", meetRoomApplyEntity.getSourceid());
            sql.appendSingle(" and sourcetype='{0}' ", MeetManageEntity.tableName);
            List<BasePermissionManageEntity> manageEntities = basePermissionManageService.queryByWhere(sql.toString());
            for (BasePermissionManageEntity item : manageEntities) {
                BasePermissionManageHistoryEntity historyEntity = new BasePermissionManageHistoryEntity();
                BeanUtils.copyProperties(item, historyEntity);
                historyEntity.setId(0L);
                historyEntity.setVersion(meetManageEntity.getVersion());
                historyEntity.setSourceid(ConvertUtil.convertToString(meetManageHistoryEntity.getId()));
                historyEntity.setSourcetype(MeetManageHistoryEntity.tableName);
                //保存会议管理id
                historyEntity.setBaseid(meetManageEntity.getId());
                addEntities.add(historyEntity);
            }
            if (addEntities.size() > 0) {
                basePermissionManageHistoryService.insertBatch(addEntities);
            }
            //保存人员记录历史表
            List<BasicEntity> addPersonEntities = new ArrayList<BasicEntity>();
            sql.clear();
            sql.appendSingle(" meetid={0} ", meetRoomApplyEntity.getSourceid());
            List<MeetPersonRecordEntity> personRecordEntities = meetPersonRecordService.queryByWhere(sql.toString());
            for (MeetPersonRecordEntity pitem : personRecordEntities) {
                MeetPersonRecordHistoryEntity historyEntity = new MeetPersonRecordHistoryEntity();
                BeanUtils.copyProperties(pitem, historyEntity);
                historyEntity.setId(0L);
                historyEntity.setVersion(meetManageEntity.getVersion());
                //保存会议管理id
                historyEntity.setMeethistoryid(meetManageHistoryEntity.getId());
                addPersonEntities.add(historyEntity);
            }
            if (addPersonEntities.size() > 0) {
                meetPersonRecordHistoryService.insertBatch(addPersonEntities);
            }
            List<BasicEntity> addRemindEntities = new ArrayList<BasicEntity>();
            sql.clear();
            sql.appendSingle(" sourceid={0} ", meetRoomApplyEntity.getSourceid());
            sql.appendSingle(" and sourcetype='{0}' ", MeetManageEntity.tableName);
            List<BaseRemindConfigEntity> remindEntities = baseRemindConfigService.queryByWhere(sql.toString());
            for (BaseRemindConfigEntity ritem : remindEntities) {
                BaseRemindConfigHistoryEntity historyEntity = new BaseRemindConfigHistoryEntity();
                BeanUtils.copyProperties(ritem, historyEntity);
                historyEntity.setId(0L);
                historyEntity.setSourceid(ConvertUtil.convertToString(meetManageHistoryEntity.getId()));
                historyEntity.setSourcetype(MeetManageHistoryEntity.tableName);
                //保存会议管理id
                historyEntity.setMeetid(meetManageEntity.getId());
                addRemindEntities.add(historyEntity);
            }
            if (addRemindEntities.size() > 0) {
                baseRemindConfigHistoryService.insertBatch(addRemindEntities);
            }
        }
        //非第一次发布，状态修改为发布变更中
        if (meetManageEntity.getVersion() > 0 && meetManageEntity.getRemoteroomid() != 0) {
            meetManageEntity.setState(MeetSystemConst.MeetStateEnum.SubmitChange);
            meetManageService.updateEntity(meetManageEntity);
        }
    }

    /**
     * @description: 新旧会议室申请记录为同一会议室，且开始结束时间相同，则用新记录更新旧纪录
     * @author: chengengwei
     * @date: 2021-06-29
     * @modify:
     */
    private void updateOldApplyByNewApply(MeetRoomApplyEntity meetRoomApplyEntity, MeetRoomApplyEntity entity) {
        meetRoomApplyEntity.setName(entity.getName());
        meetRoomApplyEntity.setPreparerequest(entity.getPreparerequest());
        meetRoomApplyEntity.setDocdate(entity.getDocdate());
        meetRoomApplyEntity.setHostusercode(entity.getHostusercode());
        meetRoomApplyEntity.setDocdate(entity.getDocdate());
        meetRoomApplyEntity.setPartinnerusercode(entity.getPartinnerusercode());
        meetRoomApplyEntity.setPartinnerusername(entity.getPartinnerusername());
        meetRoomApplyEntity.setPartouteruser(entity.getPartouteruser());
        meetRoomApplyEntity.setBoardcontent(entity.getBoardcontent());
        meetRoomApplyEntity.setSourcelevel(entity.getSourcelevel());
        meetRoomApplyEntity.setSourcelist(entity.getSourcelist());
        meetRoomApplyEntity.setWelcomeinfo(entity.getWelcomeinfo());
        meetRoomApplyEntity.setWelcometime(entity.getWelcometime());
        meetRoomApplyEntity.setSigninfo(entity.getSigninfo());
        meetRoomApplyEntity.setTeainfo(entity.getTeainfo());
        meetRoomApplyEntity.setOtherservice(entity.getOtherservice());
        meetRoomApplyEntity.setAttendance(entity.getAttendance());
        self.updateEntity(meetRoomApplyEntity);
    }

    /**
     * @param sourceType
     * @param sourceId
     * @param sessionUserBean
     * @description: 取消会议室审批
     * @author: wanghongwei
     * @date: 2020-11-2 17:00:06
     * @modify:
     */
    @Override
    public void cancel(String sourceType, String sourceId, SessionUserBean sessionUserBean) {
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" 1=1 ");
        sql.appendSingle(" and sourceid = '{0}'", sourceId);
        sql.appendLineSingle(" and sourcetype = '{0}'", sourceType);
        List<MeetRoomApplyEntity> meetRoomApplyList = this.queryByWhere(sql.toString());
        for (MeetRoomApplyEntity entity : meetRoomApplyList) {
            String id = ConvertUtil.convertToString(entity.getId());
            if (!StringUtil.isEmpty(id)) {
                // 取消审批并删除记录
                self.executeDelApprove(id, sessionUserBean);
                self.deleteById(id);
            }
        }
    }

    /**
     * @description: 添加会议室相关信息
     * @author: chengengwei
     * @date: 2021-05-25
     * @modify:
     */
    @Override
    public void setMeetRoomData(Map<String, Object> dataMap) {
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(" sourcetype = '{0}' and sourceid = {1} order by createon asc",
                MeetManageEntity.tableName, dataMap.get("id"));
        List<MeetRoomApplyEntity> meetRoomApplyEntities = this.queryByWhere(whereSql.toString());
        whereSql.clear();
        if (meetRoomApplyEntities.size() > 0) {
            //在meetRoomApplyEntities里取最早的remote会议室申请
            meetRoomApplyEntities.stream().filter(roomApply -> MeetRoomTypeEnum.Remote
                    .contentEquals(datacodeCache.getValueDynamic("MeetAllRoomType", ConvertUtil.convertToString(roomApply.getMeetroomid()), "id", "name")))
                    .findFirst().ifPresent(roomApply -> {
                dataMap.put(MeetRoomTypeEnum.Remote + MeetRoomApplyEntity.FieldAttendance, roomApply.getAttendance());
            });
            //在meetRoomApplyEntities里取最早的company会议室申请
            meetRoomApplyEntities.stream().filter(roomApply -> MeetRoomTypeEnum.Company
                    .contentEquals(datacodeCache.getValueDynamic("MeetAllRoomType", ConvertUtil.convertToString(roomApply.getMeetroomid()), "id", "name")))
                    .findFirst().ifPresent(roomApply -> {
                dataMap.put(MeetRoomApplyEntity.FieldSourcelist, roomApply.getSourcelist());
                dataMap.put(MeetRoomApplyEntity.FieldOtherservice, roomApply.getOtherservice());
                dataMap.put(MeetRoomApplyEntity.FieldAttendance, roomApply.getAttendance());
                dataMap.put(MeetRoomApplyEntity.FieldWelcomeinfo, roomApply.getWelcomeinfo());
                dataMap.put(MeetRoomApplyEntity.FieldWelcometime, roomApply.getWelcometime());
                dataMap.put(MeetRoomApplyEntity.FieldSigninfo, roomApply.getSigninfo());
                dataMap.put(MeetRoomApplyEntity.FieldTeainfo, roomApply.getTeainfo());
            });
        }
    }

    /**
     * @description: 会议室申请结束脚本调用
     * @author: chengengwei
     * @date: 2021-06-01
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void afterApplySuccessfullyFlow(MeetRoomApplyEntity meetRoomApplyEntity) {
        this.createWorkScheduleForExtraUser(meetRoomApplyEntity);
        this.sendMessageToApplyAndCustomerSupplyUser(meetRoomApplyEntity);
    }

    /**
     * @description: 判断会议室是否时间冲突
     * @author: chengengwei
     * @date: 2021-07-31
     * @modify:
     */
    @Override
    public boolean checkTimeConflict(Map<String, Object> dataMap) {
        String meetroomid = ConvertUtil.convertToString(dataMap.get("meetroomid"));
        String begintime = ConvertUtil.convertToString(dataMap.get("begintime"));
        String endtime = ConvertUtil.convertToString(dataMap.get("endtime"));
        String meetroomtype = ConvertUtil.convertToString(dataMap.get("meetroomtype"));
        long meetid = ConvertUtil.convertToLong(dataMap.get("id"));
        StringBufferProxy whereSql = new StringBufferProxy();
        boolean result = false;
        // 根据会议室类型进行分情况判断
        if (MeetRoomTypeEnum.Company.equals(meetroomtype)) {
            whereSql.appendSingle(" enabled=1 and state in (1,9) and meetroomid is not null and endtime > {0} " +
                            "and begintime < {1} and meetroomid = {2}", SQLAdapter.toDateLong(begintime),
                    SQLAdapter.toDateLong(endtime), meetroomid);
            // 排除当前会议的当前类型的会议室申请记录
            if (meetid != 0) {
                whereSql.appendSingle(" and ( sourcetype != '{0}' or sourceid != {1} ) ",
                        MeetManageEntity.tableName, meetid);
            }
            result = this.getCount(whereSql.toString()) > 0;
        } else if (MeetRoomTypeEnum.Dept.equals(meetroomtype)) {
            whereSql.appendSingle(" enabled=1 and state in (1) and meetroomid is not null and endtime > {0} " +
                            "and begintime < {1} and meetroomtype = '{2}' and meetroomid = '{3}' ",
                    SQLAdapter.toDateLong(begintime), SQLAdapter.toDateLong(endtime), MeetRoomTypeEnum.Dept,
                    meetroomid);
            if (meetid != 0) {
                whereSql.appendSingle(" and id != {0} ", meetid);
            }
            result = this.meetManageService.getCount(whereSql.toString()) > 0;
        }
        return result;
    }

    /**
     * @param
     * @return
     * @throws
     * @description: 查询给定范围 30分钟内 有无会议室申请
     * @author xinfushuo
     * @date 2022/6/7
     * @modify
     */
    @Override
    public boolean checkTimeCollison(Date begin, Date end, String meetRoomId) {
        StringBufferProxy sql = new StringBufferProxy();
        SimpleDateFormat sp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sql.appendSingle("state = 9 ");
        sql.appendSingle("and meetroomid = '{0}'", meetRoomId);
        //延长范围 检测冲突 有冲突则为碰撞
        Calendar b = Calendar.getInstance();
        b.setTime(begin);
        b.add(Calendar.MINUTE, -30);
        Calendar e = Calendar.getInstance();
        e.setTime(end);
        e.add(Calendar.MINUTE, 30);
        sql.appendSingle("and endtime >= {0} and begintime <={1} ", SQLAdapter.toDateLong(sp.format(b.getTime())), SQLAdapter.toDateLong(sp.format(e.getTime())));
        List<MeetRoomApplyEntity> roomApplyEntities = this.queryByWhere(sql.toString());
        return roomApplyEntities.size() > 0;
    }

    /**
     * 发送消息给会议室申请第一个节点审批人
     *
     * @description:
     * @author: chengengwei
     * @date: 2021-08-05
     * @modify:
     */
    @Override
    public void remindFirstNodeApprovalUser(MeetRoomApplyEntity meetRoomApplyEntity) {
        List<CboRoleEntity> cboRoleEntities = cboRoleService.queryByWhere(" code = '" +
                MeetSystemConst.CustomerSupply + "' ");
        if (cboRoleEntities.size() > 0) {
            // 接收通知的人员
            List<Map<String, Object>> userList = baseCboUserExtendService.searchUserByRoleIds(ConvertUtil.
                    convertToString(cboRoleEntities.get(0).getId()));
            // 消息主题
            String subject = BaseRemindTemplate.AppRemindTemplate.RemindApplyRoomSubjectTemplate;
            // 消息内容
            String content = BaseRemindTemplate.AppRemindTemplate.RemindApplyRoomContentTemplate;
            // 当前时间
            Date now = new Date();
            // 消息列表
            List<BasicEntity> pushList = new ArrayList<>();
            userList.forEach(user -> {
                BaseRemindTaskEntity remindTaskEntity = new BaseRemindTaskEntity();
                remindTaskEntity.setContent(content);
                remindTaskEntity.setCreateon(now);
                remindTaskEntity.setModifiedon(now);
                remindTaskEntity.setNoticetype(BaseSystemConst.NoticeTypeEnum.App);
                remindTaskEntity.setSourceaction(BaseSystemConst.BaseActionType.Create);
                remindTaskEntity.setSourcetype(MeetRoomApplyEntity.tableName);
                remindTaskEntity.setSourceid(ConvertUtil.convertToString(meetRoomApplyEntity.getId()));
                remindTaskEntity.setFormtype(MeetRoomApplyEntity.tableName);
                remindTaskEntity.setFormid(ConvertUtil.convertToString(meetRoomApplyEntity.getId()));
                remindTaskEntity.setRemindtime(now);
                remindTaskEntity.setState(0);
                remindTaskEntity.setSubject(subject);
                remindTaskEntity.setUsercode(user.get("code").toString());
                remindTaskEntity.setUserid(ConvertUtil.convertToLong(user.get("id")));
                remindTaskEntity.setUsername(user.get("name").toString());
                pushList.add(remindTaskEntity);
            });
            // 插入消息
            baseRemindTaskService.insertBatch(pushList);
        }
    }

    /**
     * 给额外通知人员创建日程
     *
     * @description:
     * @author: chengengwei
     * @date: 2021-06-01
     * @modify:
     */
    private void createWorkScheduleForExtraUser(MeetRoomApplyEntity meetRoomApplyEntity) {
        List<CboRoleEntity> cboRoleEntities = cboRoleService.queryByWhere(" code = '" +
                MeetSystemConst.ApplyRoomExtraNotice + "' ");
        if (cboRoleEntities.size() > 0) {
            // 接收通知的人员
            List<Map<String, Object>> userList = baseCboUserExtendService.searchUserByRoleIds(ConvertUtil.
                    convertToString(cboRoleEntities.get(0).getId()));
            // 处理人员数据
            Map<String, Object> selectUsers = new HashMap<>();
            String usercodes = userList.stream().map(user -> ConvertUtil.convertToString(user.get("code")))
                    .collect(Collectors.joining(","));
            String usernames = userList.stream().map(user -> ConvertUtil.convertToString(user.get("name")))
                    .collect(Collectors.joining(","));
            selectUsers.put("usercodes", usercodes);
            selectUsers.put("usernames", usernames);
            List<BasePermissionManageEntity> permissionList = ((BasePermissionManageService) SpringUtil
                    .getBean("basePermissionManageService")).processSelectUsers(
                    selectUsers, MeetSystemConst.MeetPersonTypeEnum.Attend, meetRoomApplyEntity.getUsercode(),
                    meetRoomApplyEntity.getUsername());
            // 生成提醒配置实例
            List<BaseRemindConfigEntity> remindEntityList = new ArrayList<>();
            BaseRemindConfigEntity baseRemindConfigEntity = new BaseRemindConfigEntity();
            baseRemindConfigEntity.setRemindtype(BaseSystemConst.RemindTypeEnum.EarlierBegintime);
            baseRemindConfigEntity.setUnit(BaseSystemConst.RemindUnitTypeEnum.Day);
            baseRemindConfigEntity.setNoticetype(BaseSystemConst.NoticeTypeEnum.App);
            baseRemindConfigEntity.setId(0);
            baseRemindConfigEntity.setSortCode(0);
            baseRemindConfigEntity.setValue(RemindTime);
            remindEntityList.add(baseRemindConfigEntity);
            // 生成日程实例
            WorkScheduleEntity workScheduleEntity = new WorkScheduleEntity();
            workScheduleEntity.setBegintime(meetRoomApplyEntity.getBegintime());
            workScheduleEntity.setEndtime(meetRoomApplyEntity.getEndtime());
            workScheduleEntity.setScheduletype(WorkSystemConst.WorkSourceTypeEnum.MeetManageType);
            workScheduleEntity.setName(WorkTitle);
            workScheduleEntity.setSourceapp(WorkSystemConst.WorkSourceAppEnum.Work);
            workScheduleEntity.setSourceid(ConvertUtil.convertToString(meetRoomApplyEntity.getId()));
            workScheduleEntity.setSourcetype(MeetRoomApplyEntity.tableName);
            workScheduleEntity.setHandleusercode(meetRoomApplyEntity.getUsercode());
            workScheduleEntity.setTemplatetype(Templatetype);
            // 获取会议室申请人部门全称进行拼接
            CboDeptEntity cboDeptEntity = ((CboDeptService) SpringUtil.getBean("cboDeptService"))
                    .queryObjectByWhere(" code = '" + meetRoomApplyEntity.getDeptcode() + "' ");
            workScheduleEntity.setHandleusername(cboDeptEntity.getFullname() + "\\" + meetRoomApplyEntity.getUsername());
            workScheduleEntity.setPlace(meetRoomApplyEntity.getAirlinecompany());
            // 日程对接
            ((WorkScheduleService) SpringUtil.getBean("workScheduleService"))
                    .submitWorkSchedule(workScheduleEntity, permissionList, remindEntityList, true, true);
        }
    }

    /**
     * 给申请人和客供部同事发通知
     *
     * @description:
     * @author: chengengwei
     * @date: 2021-06-01
     * @modify:
     */
    private void sendMessageToApplyAndCustomerSupplyUser(MeetRoomApplyEntity meetRoomApplyEntity) {
        List<CboRoleEntity> cboRoleEntities = cboRoleService
                .queryByWhere(" code = '" + MeetSystemConst.CustomerSupply + "' ");
        if (cboRoleEntities.size() > 0) {
            // 接收通知的人员
            List<Map<String, Object>> userList = baseCboUserExtendService.searchUserByRoleIds(ConvertUtil.
                    convertToString(cboRoleEntities.get(0).getId()));
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("code", meetRoomApplyEntity.getUsercode());
            userMap.put("name", meetRoomApplyEntity.getUsername());
            userList.add(userMap);
            // 处理人员数据
            userList = userList.stream().map(user -> {
                Map<String, Object> tempMap = new HashMap<>();
                tempMap.put("code", user.get("code"));
                tempMap.put("name", user.get("name"));
                return tempMap;
            }).distinct().collect(Collectors.toList());
            this.sendMessage(userList, meetRoomApplyEntity);
        }
    }

    /**
     * 给申请人和客供部同事发通知
     *
     * @description:
     * @author: chengengwei
     * @date: 2021-06-01
     * @modify:
     */
    private void sendMessage(List<Map<String, Object>> userList, MeetRoomApplyEntity meetRoomApplyEntity) {
        // 发送消息提醒
        List<BasicEntity> remindTaskList = new ArrayList<>();
        // 查询会议室名称
        MeetRoomManageEntity meetRoomManageEntity = this.meetRoomManageService
                .queryById(ConvertUtil.convertToString(meetRoomApplyEntity.getMeetroomid()));
        StringBuffer roomName = new StringBuffer();
        roomName.append(meetRoomManageEntity.getName());
        // 查询会议室申请确认人员
        List<CboRoleEntity> cboRoleEntities = cboRoleService
                .queryByWhere(" code = '" + MeetSystemConst.ApplyRoomExtraNotice + "' ");
        StringBuffer userNames = new StringBuffer();
        if (cboRoleEntities.size() > 0) {
            // 接收通知的人员
            List<Map<String, Object>> extraUserList = baseCboUserExtendService.searchUserByRoleIds(ConvertUtil.
                    convertToString(cboRoleEntities.get(0).getId()));
            userNames.append(extraUserList.stream().map(user -> ConvertUtil.convertToString(user.get("name")))
                    .collect(Collectors.joining("、")));
        }
        userList.forEach(user -> {
            BaseRemindTaskEntity baseRemindTaskEntity = new BaseRemindTaskEntity();
            baseRemindTaskEntity.setUsercode(ConvertUtil.convertToString(user.get("code")));
            baseRemindTaskEntity.setUsername(ConvertUtil.convertToString(user.get("name")));
            baseRemindTaskEntity.setSourceid(ConvertUtil.convertToString(meetRoomApplyEntity.getId()));
            baseRemindTaskEntity.setSourcetype(MeetRoomApplyEntity.tableName);
            baseRemindTaskEntity.setSourceaction(BaseSystemConst.BaseActionType.Remind);
            baseRemindTaskEntity.setRemindtime(new Date());
            baseRemindTaskEntity.setSubject(BaseRemindTemplate.AppRemindTemplate.RemindMeetingConfirmedSubjectTemplate);
            baseRemindTaskEntity.setNoticetype(BaseSystemConst.NoticeTypeEnum.App);
            String content = String.format(BaseRemindTemplate.AppRemindTemplate.RemindMeetingConfirmedContentTemplate,
                    meetRoomApplyEntity.getName(), roomName.toString(), userNames.toString());
            baseRemindTaskEntity.setContent(content);
            remindTaskList.add(baseRemindTaskEntity);
        });
        this.baseRemindTaskService.insertBatch(remindTaskList);
    }

    @SneakyThrows
    @Override
    protected void afterApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns, CboApprovalNodeEntity node, SessionUserBean sessionUserBean) {
        super.afterApprove(billEntity, nodeIns, node, sessionUserBean);
        MeetRoomApplyEntity roomApplyEntity = (MeetRoomApplyEntity) billEntity;
        int state = roomApplyEntity.getState();
        //如果是审批退回
        if (TapSystemConst.TapApprovalFlowStateEnum.Back == state) {
            MeetRoomManageEntity roomManageEntity = meetRoomManageService.queryById(ConvertUtil.convertToString(roomApplyEntity.getMeetroomid()));
            //查询最新会议信息
            MeetManageEntity manageEntity = meetManageService.queryById(roomApplyEntity.getSourceid());
            //如果会议室申请已关联腾讯会议 则进行取消处理
            this.cancelTencentMeet(roomApplyEntity);
            //大于等于0是限制历史数据
            if (manageEntity != null && manageEntity.getVersion() >= 0) {
                MeetRoomManageEntity meetRoom = meetRoomManageService.queryById(ConvertUtil.convertToString(roomApplyEntity.getMeetroomid()));
                //如果是远程会议审批
                if (manageEntity.getRemoteroomid() != 0 && MeetRoomTypeEnum.Remote.equals(meetRoom.getType())) {
                    //删除最大版本号的会议管理历史数据
                    MeetManageHistoryEntity maxVersionManage = meetManageHistoryService.queryObjectByWhere(" meetid=" + roomApplyEntity.getSourceid() + " and version=" + manageEntity.getVersion());
                    if (maxVersionManage != null) {
                        meetManageHistoryService.deleteByWhere(" id=" + maxVersionManage.getId());
                        basePermissionManageHistoryService.deleteByWhere(" sourcetype='MeetManageHistory' and sourceid=" + maxVersionManage.getId());
                        baseRemindConfigHistoryService.deleteByWhere(" sourcetype='MeetManageHistory' and sourceid=" + maxVersionManage.getId());
                        meetPersonRecordHistoryService.deleteByWhere(" meethistoryid=" + maxVersionManage.getId());
                    }
                    //回退状态
                    //发布中
                    int updateState = MeetSystemConst.MeetStateEnum.Save;
                    if (manageEntity.getState() == MeetSystemConst.MeetStateEnum.SubmitChange) {
                        //发布变更中
                        updateState = MeetSystemConst.MeetStateEnum.Publish;
                    }
                    //使用之前版本信息新覆盖会议管理表
                    MeetManageHistoryEntity oldVersionManage = meetManageHistoryService.queryObjectByWhere(MeetManageHistoryEntity.FieldMeetid + " = " + roomApplyEntity.getSourceid() + " and version=" + (manageEntity.getVersion() - 1));
                    if (oldVersionManage != null) {
                        MeetManageEntity updateManageEntity = new MeetManageEntity();
                        BeanUtils.copyProperties(oldVersionManage, updateManageEntity);
                        updateManageEntity.setId(manageEntity.getId());
                        updateManageEntity.setState(updateState);
                        meetManageService.updateEntity(updateManageEntity);
                        //回滚人员权限表、人员记录表，先删除
                        basePermissionManageService.deleteByWhere(" sourcetype='MeetManage' and sourceid=" + manageEntity.getId());
                        baseRemindConfigService.deleteByWhere(" sourcetype='MeetManage' and sourceid=" + manageEntity.getId());
                        meetPersonRecordService.deleteByWhere(" meetid=" + manageEntity.getId());
                        //获取历史表数据
                        // 人员权限表
                        List<BasicEntity> addEntities = new ArrayList<BasicEntity>();
                        List<BasePermissionManageHistoryEntity> manageEntities = basePermissionManageHistoryService.queryByWhere(" sourcetype='MeetManageHistory' and sourceid=" + oldVersionManage.getId());
                        for (BasePermissionManageHistoryEntity item : manageEntities) {
                            BasePermissionManageEntity tempEntity = new BasePermissionManageEntity();
                            BeanUtils.copyProperties(item, tempEntity);
                            tempEntity.setId(0L);
                            tempEntity.setSourceid(ConvertUtil.convertToString(manageEntity.getId()));
                            tempEntity.setSourcetype(MeetManageEntity.tableName);
                            addEntities.add(tempEntity);
                        }
                        if (addEntities.size() > 0) {
                            basePermissionManageService.insertBatch(addEntities);
                        }
                        //保存人员记录历史表
                        List<BasicEntity> addPersonEntities = new ArrayList<BasicEntity>();
                        List<MeetPersonRecordHistoryEntity> personRecordEntities = meetPersonRecordHistoryService.queryByWhere(" meethistoryid=" + oldVersionManage.getId());
                        for (MeetPersonRecordHistoryEntity pitem : personRecordEntities) {
                            MeetPersonRecordEntity tempEntity = new MeetPersonRecordEntity();
                            BeanUtils.copyProperties(pitem, tempEntity);
                            tempEntity.setId(0L);
                            //保存会议管理id
                            tempEntity.setMeetid(ConvertUtil.convertToString(manageEntity.getId()));
                            addPersonEntities.add(tempEntity);
                        }
                        if (addPersonEntities.size() > 0) {
                            meetPersonRecordService.insertBatch(addPersonEntities);
                        }
                        // 人员权限表
                        List<BasicEntity> remindEntities = new ArrayList<BasicEntity>();
                        List<BaseRemindConfigHistoryEntity> addRemindEntities = baseRemindConfigHistoryService.queryByWhere(" sourcetype='MeetManageHistory' and sourceid=" + oldVersionManage.getId());
                        for (BaseRemindConfigHistoryEntity ritem : addRemindEntities) {
                            BaseRemindConfigEntity tempEntity = new BaseRemindConfigEntity();
                            BeanUtils.copyProperties(ritem, tempEntity);
                            tempEntity.setId(0L);
                            tempEntity.setSourceid(ConvertUtil.convertToString(manageEntity.getId()));
                            tempEntity.setSourcetype(MeetManageEntity.tableName);
                            remindEntities.add(tempEntity);
                        }
                        if (remindEntities.size() > 0) {
                            baseRemindConfigService.insertBatch(remindEntities);
                        }
                    } else {
                        manageEntity.setState(updateState);
                        meetManageService.updateEntity(manageEntity);
                    }
                    //如果有线下未审批完成的单据，进行取消
                    Map<String, Object> outSelect = new HashMap<>();
                    outSelect.put("meetid", roomApplyEntity.getSourceid());
                    outSelect.put("roomtype", MeetRoomTypeEnum.Company);
                    this.deleteUselessMeetRoomApply(outSelect);
                }
            }
        }
    }

    @Override
    public void deleteUselessMeetRoomApply(Map<String, Object> outSelect) {
        List<Map<String, Object>> outLineInfo = this.queryMap(outSelect, "queryOutLineMeetApply");
        if (outLineInfo.size() > 0) {
            // 取消之前的会议室审批并删除记录
            self.executeDelApprove(ConvertUtil.convertToString(outLineInfo.get(0).get("id")), getSessionUserBean());
//            self.deleteById(ConvertUtil.convertToString(outLineInfo.get(0).get("id")));
        }
    }

    /**
     * @param meetRoomApplyEntity
     * @return void
     * @description: 审批通过更新会议相关历史表
     * @author: wangxinhua
     * @date: 2023/3/30 14:01
     * @modify:
     */
    @Override
    public void updateMeetHistoryInfo(MeetRoomApplyEntity meetRoomApplyEntity) {
        //查询最新会议信息
        MeetManageEntity manageEntity = meetManageService.queryById(meetRoomApplyEntity.getSourceid());
        MeetRoomManageEntity meetRoom = meetRoomManageService.queryById(ConvertUtil.convertToString(meetRoomApplyEntity.getMeetroomid()));
        //如果公司级腾讯会议，限制发一次消息
        if (manageEntity.getRemoteroomid() != 0 && MeetRoomTypeEnum.Remote.equals(meetRoom.getType())) {
            //更新会议为已发布状态
            updateMeetToPublish(ConvertUtil.convertToString(manageEntity.getId()));
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendSingle(" meetid={0}", meetRoomApplyEntity.getSourceid());
            //更新所有的历史失效
            Map<String, Object> updateMap = new HashMap<>();
            updateMap.put(MeetManageHistoryEntity.FieldValid, 0);
            meetManageHistoryService.updateByWhere(updateMap, sql.toString());
            //更新与会议信息相同的版本号的有效状态
            sql.appendSingle(" and version=" + manageEntity.getVersion());
            updateMap.put(MeetManageHistoryEntity.FieldValid, 1);
            // 更新远程会议信息
            updateMap.put(MeetManageEntity.FieldRemotemeetinfo, manageEntity.getRemotemeetinfo());
            meetManageHistoryService.updateByWhere(updateMap, sql.toString());
            meetManageService.publishAfterApproval(manageEntity);
        }
    }

    /**
     * @param
     * @return void
     * @description: 删除线上会议之前申请的会议室
     * @author: hudeyong
     * @date: 2023/3/30 14:33
     * @modify:
     */
    @Override
    public void deleteMeetRoomApply(MeetRoomApplyEntity meetRoomApplyEntity) {
        StringBufferProxy sql = new StringBufferProxy();
        String meetRoomid = ConvertUtil.convertToString(meetRoomApplyEntity.getMeetroomid());
        MeetRoomManageEntity roomManageEntity = meetRoomManageService.queryById(meetRoomid);
        if (roomManageEntity != null && MeetRoomTypeEnum.Remote.equals(roomManageEntity.getType())) {
            sql.clear();
            sql.appendSingle("SOURCEID = '{0}' and id != '{1}' and MEETROOMID not in (select id from MEETROOMMANAGE where type != 'remote')", meetRoomApplyEntity.getSourceid(), meetRoomApplyEntity.getId());
            List<MeetRoomApplyEntity> roomApplyEntities = this.queryByWhere(sql.toString());
            for (MeetRoomApplyEntity roomApplyEntity : roomApplyEntities) {
                String id = ConvertUtil.convertToString(roomApplyEntity.getId());
                self.executeDelApprove(id, this.getSessionUserBean());
                self.deleteById(id);
            }
        }
    }

    private void updateMeetToPublish(String meetid) {
        HashMap<String, Object> updateMap = new HashMap<>();
        updateMap.put(MeetManageEntity.FieldState, MeetSystemConst.MeetStateEnum.Publish);
        updateMap.put(MeetManageEntity.FieldId, meetid);
        meetManageService.update(updateMap);
    }

    /**
     * 判断冲突并创建腾讯会议，返回主持人密钥及会议号
     *
     * @param entity MeetRoomApply
     * @author xinfushuo
     * @date 2023/3/31
     * @modify
     */
    @Override
    public void createTencentMeet(MeetRoomApplyEntity entity) throws WemeetSdkException, IOException {
            MeetRoomManageEntity roomManageEntity = meetRoomManageService.queryById(ConvertUtil.convertToString(entity.getMeetroomid()));
            // 非线上会议室直接返回
            if (!roomManageEntity.getType().contentEquals(MeetRoomTypeEnum.Remote)) {
                return;
            }
            //获取会议室关联所有列表
            List<MeetingInfo> meetingInfos = this.getAllFutureMeeting(ConvertUtil.convertToString(entity.getMeetroomid()));
            Date startTime = entity.getBegintime();
            Date endTime = entity.getEndtime();
            if (validateExist(entity, meetingInfos)) {
                log.info("会议" + entity.getRemotemeetinfo() + "已经存在！");
                ObjectMapper mapper = new ObjectMapper();
                MeetingInfo meetingInfo = mapper.readValue(entity.getRemotemeetinfo(), MeetingInfo.class);
                //更新主表创建消息
                afterCreateTencent(entity, meetingInfo);
                return;
            }
            List<MeetRoomApplyEntity> thisMeetApply = self.queryByWhere("sourceid = '" + entity.getSourceid() + "'" + "and id ! = '" + entity.getId() + "'");
            //去除当前会议关联的线上会议信息
            if (thisMeetApply != null && !thisMeetApply.isEmpty())
                meetingInfos = meetingInfos.stream().filter(meetingInfo ->
                        thisMeetApply.stream().map(apply->ConvertUtil.convertToString(apply.getRemotemeetinfo())).noneMatch(info -> info.contains(meetingInfo.getMeetingId()))
                ).collect(Collectors.toList());
            //进行冲突检测
            boolean hasConflict = !meetingInfos.isEmpty() && meetingInfos.stream().anyMatch(meetingInfo -> {
                Date online_start = DateTime.of(Long.parseLong(meetingInfo.getStartTime()) * 1000);
                Date online_end = DateTime.of(Long.parseLong(meetingInfo.getEndTime()) * 1000);
                return online_start.compareTo(endTime) <= 0 && online_end.compareTo(startTime) >= 0;
            });
            //没有冲突
            if (!hasConflict) {
                //创建会议
                MeetingInfo meetingInfo = self.callCreateApi(entity.getName(), getUserid(ConvertUtil.convertToString(entity.getMeetroomid())), entity.getBegintime(), entity.getEndtime());
                entity.setRemotemeetinfo(JSONUtil.toJsonStr(meetingInfo));
                self.updateMeetRoomAppy(entity);
                //构建创建后消息 更新主表
                afterCreateTencent(entity, meetingInfo);
            } else {
                throw new ServiceException("腾讯会议线上会议室时间存在冲突，请联系公司腾讯会议管理员进行处理");
            }
    }

    /**
     * 成功创建后 发送消息 更新主表
     *
     * @param
     * @return
     * @throws
     * @author xinfushuo
     * @date 2023/4/6
     * @modify
     */
    public void afterCreateTencent(MeetRoomApplyEntity entity, MeetingInfo meetingInfo) {
        Date startTime = entity.getBegintime();
        StringBufferProxy content = new StringBufferProxy();
        content.appendSingle(BaseRemindTemplate.MeetRoomApplyTemplate.RemoteMeetContent, WorkScheduleService.getDateStringWithWeek(startTime), meetingInfo.getSubject(), meetingInfo.getMeetingCode(), meetingInfo.getHostKey());
        meetManageService.sendMessageToMeetCreatorAndMessager(entity.getSourceid(), BaseRemindTemplate.MeetRoomApplyTemplate.RemoteMeetSubject, content.toString(), BaseSystemConst.BaseActionType.Create, BaseRemindTemplate.MeetRoomApplyTemplate.RemoteMeetSourceType, entity.getSourceid());
        Map<String, Object> updateMap = new HashMap<>();
        updateMap.put("id", entity.getSourceid());
        updateMap.put(MeetManageEntity.FieldRemotemeetinfo, entity.getAirlinecompany() + "(腾讯会议号" + meetingInfo.getMeetingCode() + ")");
        meetManageService.update(updateMap);
    }

    /**
     * 根据会议室关联信息 判断是否已存在线上会议
     *
     * @param
     * @return
     * @author xinfushuo
     * @date 2023/4/6
     * @modify
     */
    private boolean validateExist(MeetRoomApplyEntity entity, List<MeetingInfo> meetingInfos) throws IOException {
        String remoteInfo = entity.getRemotemeetinfo();
        //不是json字符串
        if (!JSONUtil.isJson(remoteInfo)) {
            return false;
        }
        ObjectMapper mapper = new ObjectMapper();
        MeetingInfo meetingInfo = mapper.readValue(remoteInfo, MeetingInfo.class);
        return meetingInfos.stream().anyMatch(info -> info.getMeetingId().contentEquals(meetingInfo.getMeetingId()));
    }

    /**
     * 绕开事务，只根据腾讯请求回写
     *
     * @author xinfushuo
     * @date 2023/4/4
     * @modify
     */
    public void updateMeetRoomAppy(MeetRoomApplyEntity entity) {
        //开启新线程进行更新
        ThreadUtil.execAsync(() -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", entity.getId());
            map.put(MeetRoomApplyEntity.FieldRemotemeetinfo, entity.getRemotemeetinfo());
            self.update(map);
        });
    }

    /**
     * 获取用户所有会议列表
     *
     * @param meetRoomId
     * @return
     * @author xinfushuo
     * @date 2023/4/4
     * @modify
     */
    private List<MeetingInfo> getAllFutureMeeting(String meetRoomId) throws WemeetSdkException {
        return callTecentQueryUserMeetingAPI(0, getUserid(meetRoomId));
    }

    /**
     * 递归方法 列表一次返回20个 需要递归返回
     *
     * @param pos    分页起始位置
     * @param userid 会议室绑定id
     * @return
     * @throws WemeetSdkException
     * @author xinfushuo
     * @date 2023/4/4
     * @modify
     */
    private List<MeetingInfo> callTecentQueryUserMeetingAPI(Integer pos, String userid) throws WemeetSdkException {
        try {
            QueryUserMeetingsRequest request = new QueryUserMeetingsRequest();
            request.setInstanceId(InstanceEnum.INSTANCE_PC.getInstanceID());
            request.setPos(pos);
            request.setUserId(userid);
            if (userid == null || userid.isEmpty()) {
                throw new WemeetSdkException(Integer.parseInt(RestErrorCode.USER_NOT_EXIST), "用户参数不允许为空");
            }
            QueryUserMeetingsResponse response = TencentMeetUtil.MEETING_CLIENT.queryUserMeetings(request);
            List<MeetingInfo> meetingInfos = new ArrayList<>(response.getMeetingInfoList());
            if (response.getRemaining() != 0) {
                //开始递归
                meetingInfos.addAll(callTecentQueryUserMeetingAPI(response.getNextPos(), userid));
            }
            return meetingInfos;
        } catch (WemeetSdkException e) {
            if (RestErrorCode.USER_NOT_EXIST.contentEquals(ConvertUtil.convertToString(e.getCode()))) {
                throw new ServiceException("当前会议室尚未关联有效线上账号，请联系管理员处理。");
            }
            throw new ServiceException("系统请求腾讯会议失败，请稍后重试或联系管理员。");
        }
    }

    /**
     * 根据Roomid 获取腾讯会议账号id
     *
     * @param
     * @author xinfushuo
     * @date 2023/4/1
     * @modify
     */
    @Override
    public String getUserid(String meetRoomid) {
        MeetRoomManageEntity roomManageEntity = meetRoomManageService.queryById(meetRoomid);
        String roomParam = roomManageEntity.getExtraparam();
        JSONObject json = JSONUtil.isJson(roomParam) ? JSONUtil.parseObj(roomParam) : new JSONObject();
        String userid = "";
        if (!json.isEmpty()) {
            userid = ConvertUtil.convertToString(json.get("userid"));
        }
        return userid;
    }

    /**
     * 调用腾讯会议创建接口
     *
     * @param
     * @return
     * @throws
     * @author xinfushuo
     * @date 2023/4/1
     * @modify
     */
    public MeetingInfo callCreateApi(String subject, String userid, Date begin, Date end) throws WemeetSdkException {
        try {
            CreateMeetingRequest createRequest = new CreateMeetingRequest();
            createRequest.setInstanceId(InstanceEnum.INSTANCE_PC.getInstanceID());
            //主题
            createRequest.setSubject(subject);
            //用户id
            createRequest.setUserId(userid);
            //普通预约会议
            createRequest.setType(0);
            //普通非周期会议
            createRequest.setMeetingType(0);
            // 开启主持密钥
            createRequest.setEnableHostKey(true);
            createRequest.setEnableDocUploadPermission(false);
            //开始结束时间
            createRequest.setStartTime(ConvertUtil.convertToString(begin.getTime() / 1000));
            createRequest.setEndTime(ConvertUtil.convertToString(end.getTime() / 1000));
            //配置个性配置
            MeetingSetting setting = new MeetingSetting();
            //不允许会议提前进入
            setting.setAllowInBeforeHost(false);
            //开启等候室
            setting.setAutoInWaitingRoom(true);
            //配置设置
            createRequest.setSettings(setting);
            QueryMeetingDetailResponse createResponese = TencentMeetUtil.MEETING_CLIENT.createMeeting(createRequest);
            return createResponese.getMeetingInfoList().get(0);
        } catch (WemeetSdkException exception) {
            if (RestErrorCode.USER_NOT_EXIST.contentEquals(ConvertUtil.convertToString(exception.getCode()))) {
                throw new ServiceException("当前会议室尚未关联有效线上账号，请联系管理员处理。");
            }
            throw new ServiceException("系统请求腾讯会议失败，请稍后重试或联系管理员。");
        }
    }

    /**
     * @author: zhangsui
     * @date: 2017年3月6日下午4:44:14
     * @params: @param id
     * @description:取消审批
     * @modify:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeDelApprove(String id, SessionUserBean sessionUserBean) {
        // 查询实体
        TapEntity entity = this.queryById(id);
        if (entity == null) {
            return;
        }
        try {
            beforeDelApprove(entity, sessionUserBean);
        }catch (Exception e){
            e.printStackTrace();
        }
        // 删除审批信息
        StringBufferProxy sql = new StringBufferProxy();
        sql.appendSingle(" sourceid={0} ", id);
        sql.appendSingle(" and sourcetype='{0}' ", entity.getTableName());
        CboApprovalNodeInsService cboApprovalNodeInsService = (CboApprovalNodeInsService) SpringUtil
                .getBean("cboApprovalNodeInsService");
        ICboApprovalFlowInsService cboApprovalFlowInsService = (ICboApprovalFlowInsService) SpringUtil
                .getBean("cboApprovalFlowInsService");
        cboApprovalNodeInsService.deleteByWhere(sql.toString());
        cboApprovalFlowInsService.deleteByWhere(sql.toString());
        // 清除单据上的审批信息
        Map<String, Object> map_update = new HashMap<String, Object>();
        map_update.put("id", id);
        map_update.put("state", TapSystemConst.TapApprovalBillStateEnum.Open);
        map_update.put("submitdate", null);
        map_update.put(this.fieldName_latestPhase, "");
        this.update(map_update);
        afterDelApprove(entity, sessionUserBean);
    }

    /**
     * 审批不通过
     *
     * @param
     * @return
     * @throws
     * @author xinfushuo
     * @date 2023/4/1
     * @modify
     */
    @SneakyThrows
    @Override
    protected void afterDelApprove(TapEntity entity, SessionUserBean sessionUserBean) {
        super.afterDelApprove(entity, sessionUserBean);
        MeetRoomApplyEntity roomApplyEntity = (MeetRoomApplyEntity) entity;
        MeetRoomManageEntity roomManageEntity = meetRoomManageService.queryById(ConvertUtil.convertToString(roomApplyEntity.getMeetroomid()));
        // 当前申请单关联线上会议室时，取消审批取消对应线上腾讯会议室
        if (MeetRoomTypeEnum.Remote.contentEquals(roomManageEntity.getType()) && roomApplyEntity.getRemotemeetinfo() != null) {
           cancelTencentMeet(roomApplyEntity);
        }
    }
    /**
      * 取消会议室申请关联的线上会议室
      * @author xinfushuo
      * @param
      * @throws
      * @return
      * @date 2023/4/10
      * @modify
      */
    public void cancelTencentMeet(MeetRoomApplyEntity roomApplyEntity) throws IOException {
        //取消会议
        MeetingInfo meetingInfo;
        ObjectMapper mapper = new ObjectMapper();
        //未关联实际线上会议
        if (!JSONUtil.isJson(roomApplyEntity.getRemotemeetinfo())) {
            return;
        }
        meetingInfo = mapper.readValue(roomApplyEntity.getRemotemeetinfo(), MeetingInfo.class);
        if (meetingInfo != null) {
            self.updateEntity(roomApplyEntity);
            //取消会议后 取消线上
            CancelMeetingRequest request = new CancelMeetingRequest();
            request.setInstanceId(InstanceEnum.INSTANCE_PC.getInstanceID());
            request.setUserId(getUserid(ConvertUtil.convertToString(roomApplyEntity.getMeetroomid())));
            request.setMeetingId(meetingInfo.getMeetingId());
            request.setReasonCode(0);
            request.setReasonDetail("关联会议室申请单" + roomApplyEntity.getDocno() + "取消审批。");
            try {
                TencentMeetUtil.MEETING_CLIENT.cancelMeeting(request);
            } catch (WemeetSdkException e) {
                String errorCode = String.valueOf(e.getCode());
                switch (errorCode) {
                    //会议已被取消
                    case RestErrorCode.MEET_CANCELED:
                        return;
                    //会议正在进行
                    case RestErrorCode.MEET_ONGOING_CANT_CANCEL:
                        throw new ServiceException("申请所关联的腾讯会议" + meetingInfo.getMeetingCode() + "正在进行中,无法取消");
                }
                throw new ServiceException("系统请求腾讯会议失败，请稍后重试或联系管理员");
            }
        }
    }
}
